package app.common.utils.dingtalk;

import app.common.utils.dingtalk.domain.SearchCondition;
import com.alibaba.fastjson.JSON;
import com.aliyun.dingtalkyida_1_0.models.BatchGetFormDataByIdListHeaders;
import com.aliyun.dingtalkyida_1_0.models.BatchGetFormDataByIdListRequest;
import com.aliyun.dingtalkyida_1_0.models.BatchGetFormDataByIdListResponse;
import com.aliyun.dingtalkyida_1_0.models.BatchGetFormDataByIdListResponseBody;
import com.aliyun.dingtalkyida_1_0.models.BatchRemovalByFormInstanceIdListHeaders;
import com.aliyun.dingtalkyida_1_0.models.BatchRemovalByFormInstanceIdListRequest;
import com.aliyun.dingtalkyida_1_0.models.CreateOrUpdateFormDataHeaders;
import com.aliyun.dingtalkyida_1_0.models.CreateOrUpdateFormDataRequest;
import com.aliyun.dingtalkyida_1_0.models.CreateOrUpdateFormDataResponse;
import com.aliyun.dingtalkyida_1_0.models.GetFormDataByIDHeaders;
import com.aliyun.dingtalkyida_1_0.models.GetFormDataByIDRequest;
import com.aliyun.dingtalkyida_1_0.models.GetFormDataByIDResponseBody;
import com.aliyun.dingtalkyida_1_0.models.GetInstanceByIdHeaders;
import com.aliyun.dingtalkyida_1_0.models.GetInstanceByIdRequest;
import com.aliyun.dingtalkyida_1_0.models.GetInstanceByIdResponseBody;
import com.aliyun.dingtalkyida_1_0.models.GetInstanceIdListHeaders;
import com.aliyun.dingtalkyida_1_0.models.GetInstanceIdListRequest;
import com.aliyun.dingtalkyida_1_0.models.GetInstanceIdListResponse;
import com.aliyun.dingtalkyida_1_0.models.SaveFormDataHeaders;
import com.aliyun.dingtalkyida_1_0.models.SaveFormDataRequest;
import com.aliyun.dingtalkyida_1_0.models.SaveFormDataResponse;
import com.aliyun.dingtalkyida_1_0.models.SaveFormDataResponseBody;
import com.aliyun.dingtalkyida_1_0.models.SearchFormDataIdListHeaders;
import com.aliyun.dingtalkyida_1_0.models.SearchFormDataIdListRequest;
import com.aliyun.dingtalkyida_1_0.models.SearchFormDataIdListResponse;
import com.aliyun.dingtalkyida_1_0.models.SearchFormDataIdListResponseBody;
import com.aliyun.dingtalkyida_1_0.models.UpdateFormDataHeaders;
import com.aliyun.dingtalkyida_1_0.models.UpdateFormDataRequest;
import com.aliyun.teautil.models.RuntimeOptions;
import com.gitee.feizns.dynamic.Lists;
import com.gitee.feizns.quickstart.jackson.JsonUtils;
import lombok.SneakyThrows;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

/**
 * <b>宜搭操作工具类</b>
 * @author feizns
 * @since 2022/12/30
 */
public class YiDaUtils {

    /**
     * 配置
     */
    private final app.common.utils.dingtalk.Config config;

    /**
     * {@link Auth2Utils}
     */
    private final Auth2Utils auth2Utils;

    public YiDaUtils(Auth2Utils auth2Utils) {
        this.auth2Utils = auth2Utils;
        this.config = auth2Utils.getConfig();
    }

    /**
     * 客户端
     */
    private static final com.aliyun.dingtalkyida_1_0.Client client;
    static {
        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config();
        config.protocol = "https";
        config.regionId = "central";
        try {
            client = new com.aliyun.dingtalkyida_1_0.Client(config);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 流程
     */
    public Processes processes = new Processes();

    /**
     * 表单
     */
    public Forms forms = new Forms();

    /**
     * 流程
     * @author feizns
     * @since 2023/07/18
     */
    public class Processes {

        /**
         * 获取流程实例编号列表
         * @param fromUuid 表单uuid
         * @return 实例编号列表
         */
        public List<String> getIds(String fromUuid, String systemToken, String appType, Consumer<GetInstanceIdListRequest> consumer) {
            try {
                GetInstanceIdListHeaders getInstanceIdListHeaders = new GetInstanceIdListHeaders();
                getInstanceIdListHeaders.xAcsDingtalkAccessToken = auth2Utils.getAccessToken();
                List<String> result = new ArrayList<>();
                final long pageSize = 100;
                long pageNo = 1;
                long total;
                do {
                    GetInstanceIdListRequest getInstanceIdListRequest = new GetInstanceIdListRequest()
                            .setFormUuid(fromUuid)
                            .setUserId(config.getUserId())
                            .setSystemToken(systemToken)
                            .setAppType(appType)
                            .setPageSize((int) pageSize)
                            .setPageNumber((int) pageNo);
                    consumer.accept(getInstanceIdListRequest);
                    GetInstanceIdListResponse options = client.getInstanceIdListWithOptions(getInstanceIdListRequest, getInstanceIdListHeaders, new RuntimeOptions());
                    total = options.getBody().getTotalCount();
                    result.addAll(options.getBody().getData());
                } while ((pageNo++ * pageSize) < total );
                return result;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        /**
         * 获取流程实例编号列表
         * @param fromUuid 表单uuid
         * @return 实例编号列表
         */
        public List<String> getIds(String fromUuid, Consumer<GetInstanceIdListRequest> reqConsumer) {
            return getIds(fromUuid, config.getSystemToken(), config.getAppType(), reqConsumer);
        }

        /**
         * 获取流程实例编号列表
         * @param fromUuid 表单uuid
         * @return 实例编号列表
         */
        public List<String> getIds(String fromUuid) {
            return getIds(fromUuid, config.getSystemToken(), config.getAppType(), req -> {});
        }

        /**
         * 获取对应流程实例的详情
         * @param processInstanceId 流程实例编号
         * @return {@link GetInstanceByIdResponseBody}
         */
        public GetInstanceByIdResponseBody getById(String processInstanceId) {
            GetInstanceByIdHeaders getInstanceByIdHeaders = new GetInstanceByIdHeaders();
            getInstanceByIdHeaders.xAcsDingtalkAccessToken = auth2Utils.getAccessToken();
            GetInstanceByIdRequest getInstanceByIdRequest = new GetInstanceByIdRequest()
                    .setAppType(config.getAppType())
                    .setSystemToken(config.getSystemToken())
                    .setUserId(config.getUserId())
                    .setLanguage(config.getLanguage());
            try {
                return client.getInstanceByIdWithOptions(processInstanceId, getInstanceByIdRequest, getInstanceByIdHeaders, new RuntimeOptions()).getBody();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

    }

    /**
     * 表单
     * @author feizns
     * @since 2023/07/18
     */
    public class Forms {

        /**
         * 插入
         * @param formUuid uuid形式
         * @param data 数据
         * @return {@link SaveFormDataResponseBody}
         * @throws Exception 异常
         */
        public SaveFormDataResponseBody insert(String formUuid, Map<String, Object> data) throws Exception {
            SaveFormDataHeaders saveFormDataHeaders = new SaveFormDataHeaders();
            saveFormDataHeaders.xAcsDingtalkAccessToken = auth2Utils.getAccessToken();
            SaveFormDataRequest saveFormDataRequest = new SaveFormDataRequest()
                    .setAppType(config.getAppType())
                    .setSystemToken(config.getSystemToken())
                    .setUserId(config.getUserId())
                    .setLanguage(config.getLanguage())
                    .setFormUuid(formUuid)
                    .setFormDataJson(JSON.toJSONString(data));
            SaveFormDataResponse response = client.saveFormDataWithOptions(saveFormDataRequest, saveFormDataHeaders, new RuntimeOptions());
            return response.getBody();
        }

        /**
         * 清空表单数据
         * @param frmUuid 纳uuid
         */
        public void clear(String frmUuid) {
            List<String> instanceIds = instanceIds(frmUuid);
            List<List<String>> lists = Lists.partition(instanceIds, 500);
            for (List<String> ids : lists) {
                deleteByIds(frmUuid, ids.toArray(String[]::new));
                System.out.println("删除数据：" + ids);
            }
        }

        /**
         * 删除通过实例编号
         * @param ids 编号列表
         */
        public void deleteByIds(String frmUuid, String... ids) {
            BatchRemovalByFormInstanceIdListHeaders batchRemovalByFormInstanceIdListHeaders = new BatchRemovalByFormInstanceIdListHeaders();
            batchRemovalByFormInstanceIdListHeaders.xAcsDingtalkAccessToken = auth2Utils.getAccessToken();
            BatchRemovalByFormInstanceIdListRequest batchRemovalByFormInstanceIdListRequest = new BatchRemovalByFormInstanceIdListRequest()
                    .setFormUuid(frmUuid)
                    .setAppType(config.getAppType())
                    .setAsynchronousExecution(true)
                    .setSystemToken(config.getSystemToken())
                    .setFormInstanceIdList(Arrays.asList(ids))
                    .setUserId(config.getUserId())
                    .setExecuteExpression(false);
            try {
                client.batchRemovalByFormInstanceIdListWithOptions(batchRemovalByFormInstanceIdListRequest, batchRemovalByFormInstanceIdListHeaders, new RuntimeOptions());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        /**
         * 通过表单实例编号更新
         * @param formInstanceId 形式实例编号
         * @param data 数据
         */
        public void updateById(String formInstanceId, Map<String, Object> data) {
            UpdateFormDataHeaders updateFormDataHeaders = new UpdateFormDataHeaders();
            updateFormDataHeaders.xAcsDingtalkAccessToken = auth2Utils.getAccessToken();
            UpdateFormDataRequest updateFormDataRequest = new UpdateFormDataRequest()
                    .setAppType(config.getAppType())
                    .setSystemToken(config.getSystemToken())
                    .setUserId(config.getUserId())
                    .setLanguage(config.getLanguage())
                    .setFormInstanceId(formInstanceId)
                    .setUpdateFormDataJson(JsonUtils.toJson(data));
            try {
                client.updateFormDataWithOptions(updateFormDataRequest, updateFormDataHeaders, new RuntimeOptions());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        /**
         * 根据条件抓取所有列表数据
         * @param formUuid uuid形式
         * @param conditions 条件
         * @return {@link List}<{@link GetFormDataByIDResponseBody}>
         */
        public List<BatchGetFormDataByIdListResponseBody.BatchGetFormDataByIdListResponseBodyResult> getList(String formUuid, SearchCondition... conditions) {
            List<String> instanceIds = instanceIds(formUuid, conditions);
            if ( CollectionUtils.isEmpty(instanceIds) )
                return Collections.emptyList();
            return getByIds(formUuid, instanceIds.toArray(String[]::new));
        }

        /**
         * 根据条件抓一条数据
         * @param formUuid uuid形式
         * @param conditions 条件
         * @return {@link GetFormDataByIDResponseBody}
         */
        public GetFormDataByIDResponseBody getOne(String formUuid, SearchCondition... conditions) {
            List<String> instanceIds = instanceIds(formUuid, conditions);
            return CollectionUtils.isEmpty(instanceIds) ? null : getById(instanceIds.get(0));
        }

        /**
         * 是否存在指定条件的数据
         * @param fromUuid 从uuid
         * @param conditions 条件
         * @return boolean
         */
        public boolean exists(String fromUuid, SearchCondition... conditions) {
            List<String> instanceIds = instanceIds(fromUuid, conditions);
            return !CollectionUtils.isEmpty(instanceIds);
        }

        /**
         * 得到通过编号
         * 得到形式数据通过编号
         * @param formInstanceId 形式实例编号
         * @return {@link GetFormDataByIDResponseBody}
         */
        public GetFormDataByIDResponseBody getById(String formInstanceId) {
            GetFormDataByIDHeaders getFormDataByIDHeaders = new GetFormDataByIDHeaders();
            getFormDataByIDHeaders.xAcsDingtalkAccessToken = auth2Utils.getAccessToken();
            GetFormDataByIDRequest getFormDataByIDRequest = new GetFormDataByIDRequest()
                    .setAppType(config.getAppType())
                    .setSystemToken(config.getSystemToken())
                    .setUserId(config.getUserId())
                    .setLanguage(config.getLanguage());
            try {
                return client
                        .getFormDataByIDWithOptions(formInstanceId, getFormDataByIDRequest, getFormDataByIDHeaders, new RuntimeOptions())
                        .getBody();
            } catch (Exception err) {
                throw new RuntimeException(err);
            }
        }

        /**
         * 插入或更新
         * @param fromUuid 从uuid
         * @param data 数据
         * @param condition 条件
         * @return {@link List}<{@link String}>
         */
        @SneakyThrows
        public List<String> insertOrUpdate(String fromUuid, Map<String, Object> data, SearchCondition... condition) {
            CreateOrUpdateFormDataHeaders createOrUpdateFormDataHeaders = new CreateOrUpdateFormDataHeaders();
            createOrUpdateFormDataHeaders.xAcsDingtalkAccessToken = auth2Utils.getAccessToken();
            CreateOrUpdateFormDataRequest createOrUpdateFormDataRequest = new CreateOrUpdateFormDataRequest()
                    .setNoExecuteExpression(false)
                    .setFormUuid(fromUuid)
                    .setSearchCondition(JSON.toJSONString(Arrays.asList(condition)))
                    .setAppType(config.getAppType())
                    .setFormDataJson(JSON.toJSONString(data))
                    .setSystemToken(config.getSystemToken())
                    .setUserId(config.getUserId());
            CreateOrUpdateFormDataResponse options = client.createOrUpdateFormDataWithOptions(createOrUpdateFormDataRequest, createOrUpdateFormDataHeaders, new RuntimeOptions());
            return options.getBody().getResult();
        }

        /**
         * 实例编号列表
         * @param fromUuid 从uuid
         * @param conditions 条件
         * @return {@link List}<{@link String}>
         */
        @SneakyThrows
        public List<String> instanceIds(String fromUuid, SearchCondition... conditions) {
            return instanceIds(fromUuid, null, null, null, null,conditions);
        }

        /**
         * 实例编号列表
         * @param fromUuid 从uuid
         * @param createFromTimeGMT 格林尼治时间创建时间
         * @param createToTimeGMT 格林尼治时间创建时间
         * @param conditions 条件
         * @return {@link List}<{@link String}>
         */
        @SneakyThrows
        public List<String> instanceIds(String fromUuid, String createFromTimeGMT, String createToTimeGMT, String modifiedFromTimeGMT, String modifiedToTimeGMT, SearchCondition... conditions) {
            List<String> result = new ArrayList<>();
            instanceIds(fromUuid, createFromTimeGMT, createToTimeGMT, modifiedFromTimeGMT, modifiedToTimeGMT, result::add, conditions);
            return result;
        }

        /**
         * 实例编号列表
         * @param fromUuid 从uuid
         * @param createFromTimeGMT 格林尼治时间创建时间
         * @param createToTimeGMT 格林尼治时间创建时间
         * @param conditions 条件
         * @return {@link List}<{@link String}>
         */
        @SneakyThrows
        public List<String> instanceIds(String fromUuid, String createFromTimeGMT, String createToTimeGMT, SearchCondition... conditions) {
            List<String> result = new ArrayList<>();
            instanceIds(fromUuid, createFromTimeGMT, createToTimeGMT, null, null, result::add, conditions);
            return result;
        }

        /**
         * 实例编号列表
         * @param fromUuid 从uuid
         * @param createFromTimeGMT 格林尼治时间创建时间
         * @param createToTimeGMT 格林尼治时间创建时间
         * @param conditions 条件
         */
        @SneakyThrows
        public void instanceIds(String fromUuid, String createFromTimeGMT, String createToTimeGMT, String modifiedFromTimeGMT, String modifiedToTimeGMT, Consumer<String> consumer, SearchCondition... conditions) {
            int maxPageSize = 100;
            int current = 1;
            long total = 0;
            do {
                SearchFormDataIdListHeaders searchFormDataIdListHeaders = new SearchFormDataIdListHeaders();
                searchFormDataIdListHeaders.xAcsDingtalkAccessToken = auth2Utils.getAccessToken();
                SearchFormDataIdListRequest searchFormDataIdListRequest = new SearchFormDataIdListRequest()
                        .setSystemToken(config.getSystemToken())
                        .setLanguage(config.getLanguage())
                        .setUserId(config.getUserId())
                        .setSearchFieldJson(JSON.toJSONString(Arrays.asList(conditions)))
                        .setPageNumber(current)
                        .setPageSize(maxPageSize);
                if ( createFromTimeGMT != null )
                    searchFormDataIdListRequest.setCreateFromTimeGMT(createFromTimeGMT);
                if ( createToTimeGMT != null )
                    searchFormDataIdListRequest.setCreateToTimeGMT(createToTimeGMT);
                if ( modifiedFromTimeGMT != null )
                    searchFormDataIdListRequest.setModifiedFromTimeGMT(modifiedFromTimeGMT);
                if ( modifiedToTimeGMT != null )
                    searchFormDataIdListRequest.setModifiedToTimeGMT(modifiedToTimeGMT);
                //
                SearchFormDataIdListResponse resp = client.searchFormDataIdListWithOptions(config.getAppType(), fromUuid, searchFormDataIdListRequest, searchFormDataIdListHeaders, new RuntimeOptions());
                SearchFormDataIdListResponseBody body = resp.getBody();
                total = body.getTotalCount();
                body.data.forEach(consumer);
            } while ( (long) current++ * maxPageSize < total );
        }

        /**
         * 得到通过编号列表
         * @param fromUuid 从uuid
         * @param instanceIds 实例编号列表
         * @return {@link List}<{@link BatchGetFormDataByIdListResponseBody.BatchGetFormDataByIdListResponseBodyResult}>
         */
        @SneakyThrows
        public List<BatchGetFormDataByIdListResponseBody.BatchGetFormDataByIdListResponseBodyResult> getByIds(String fromUuid, String... instanceIds) {
            BatchGetFormDataByIdListHeaders headers = new BatchGetFormDataByIdListHeaders();
            headers.xAcsDingtalkAccessToken = auth2Utils.getAccessToken();
            BatchGetFormDataByIdListRequest request = new BatchGetFormDataByIdListRequest()
                    .setFormUuid(fromUuid)
                    .setAppType(config.getAppType())
                    .setSystemToken(config.getSystemToken())
                    .setFormInstanceIdList(Arrays.asList(instanceIds))
                    .setNeedFormInstanceValue(true)
                    .setUserId(config.getUserId());
            BatchGetFormDataByIdListResponse resp = client.batchGetFormDataByIdListWithOptions(request, headers, new RuntimeOptions());
            return resp.getBody().getResult();
        }
        
    }

}
